package cvut.swe.semestralka.crawler;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

import org.apache.log4j.Logger;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;
import org.htmlcleaner.XPatherException;
import org.openrdf.model.URI;
import org.openrdf.repository.RepositoryException;
import org.springframework.beans.factory.annotation.Autowired;

import cvut.swe.semestralka.controller.CrawlerForm;
import cvut.swe.semestralka.sesame.SesameDao;

public class Crawler {
	
	private final Logger logger = Logger.getLogger(Crawler.class);
	
	@Autowired
	private SesameDao dao;
	
	//add link number or parse
	public boolean parse(Configuration configuration, CrawlerForm form ) throws CrawlerException{
		
		HtmlCleaner cleaner = new HtmlCleaner();
		try {
			//parsovat bus line
			TagNode rootNode = cleaner.clean(new URL(form.getUrl()));
			TagNode busNode = evaluateXPath(rootNode,configuration.getPathToBusNumber());
			URI busURi = dao.createLine(busNode.getText().toString()); 
			CrawlerDefaultEntity busEntity = new CrawlerDefaultEntity(busURi, busNode.getText().toString());
			TagNode lastStation = firstParsing(configuration, form, busEntity, rootNode);
			String href = lastStation.getAttributeByName("href").replaceAll("&amp;", "&");;
			if(form.getPrefix() != null && !form.getPrefix().isEmpty()){
				href = form.getPrefix() + href;
			}
			rootNode = cleaner.clean(new URL(href));
			firstParsing(configuration, form, busEntity, rootNode);
		} catch (Exception e) {
			logger.error("ouha chyba pri parsovani");
			throw new CrawlerException(e);
		}
		
		return true;
	}
	
	private TagNode firstParsing(Configuration configuration, CrawlerForm form, CrawlerDefaultEntity busEntity,TagNode rootNode) throws XPatherException, RepositoryException, MalformedURLException, IOException{
		TagNode timetableFrame = evaluateXPath(rootNode,configuration.getPathToJRFrame());
		TagNode currentStation = evaluateXPath(timetableFrame, configuration.getPathToCurrentStation());
		// current station
		String stationName = currentStation.getText().toString().replaceAll("&nbsp;", " ").trim();
		URI currentStationURI = dao.createStation(stationName);
		CrawlerDefaultEntity station = new CrawlerDefaultEntity(currentStationURI, currentStation.getText().toString());
		//get last station
		Object[] objects = timetableFrame.evaluateXPath(configuration.getPathToStations());
		Object lastObj = objects[objects.length-1];
		TagNode lastStTg =(TagNode)lastObj;
		String stationNameLast = lastStTg.getText().toString().replaceAll("&nbsp;", " ").trim();
		URI lastStationURI = dao.createStation(stationNameLast);
		CrawlerDefaultEntity lastStationEntity = new CrawlerDefaultEntity(lastStationURI, stationNameLast);
		//curent timetable
		URI timetableUri = dao.createTimetable(stationName, busEntity.getName(), lastStationEntity.getName());
		dao.addLinkToTimetable(timetableUri, busEntity.getUri());
		dao.addStationToTimeTableAsLastStation(timetableUri, lastStationURI);
		//parsing timetable
		parseTimeTable(configuration, timetableFrame, station, timetableUri, busEntity);
		//parsing available station in link
		parseStations(configuration, rootNode, form.getPrefix(),busEntity, lastStationEntity);
		
		return lastStTg;
	} 
	
	private void parseStations(Configuration cfg, TagNode tgn, String prefix, CrawlerDefaultEntity busLine, CrawlerDefaultEntity lastStationEntity) throws XPatherException, MalformedURLException, IOException, RepositoryException{
		Object[] objects = tgn.evaluateXPath(cfg.getPathToStations());
		HtmlCleaner clr = new HtmlCleaner();
		List<Object> listOfObjects = Arrays.asList(objects);
		ListIterator<Object> it = listOfObjects.listIterator();
		while(it.hasNext()){
			TagNode tg = (TagNode) it.next();
			if(!it.hasNext()){
				break;
			}
			String stationName = tg.getText().toString();
			stationName = stationName.replaceAll("&nbsp;", " ").trim();
			URI stationURI = dao.createStation(stationName);
			
			CrawlerDefaultEntity station = new CrawlerDefaultEntity(stationURI, stationName);
			String url = tg.getAttributeByName("href");
			url = url.replaceAll("&amp;", "&");
			if(prefix != null && !prefix.isEmpty()){
				url = prefix + url;
			}
			TagNode tgs = clr.clean(new URL(url));
			TagNode node = evaluateXPath(tgs,cfg.getPathToJRFrame());
			System.out.println(stationName);
			
			URI timetable = dao.createTimetable(stationName, busLine.getName(),lastStationEntity.getName());
			dao.addStationToTimetable(timetable, stationURI);
			dao.addLinkToTimetable(timetable, busLine.getUri());
			dao.addStationToTimeTableAsLastStation(timetable, lastStationEntity.getUri());
			parseTimeTable(cfg, node, station, timetable, busLine);
			
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				logger.warn("interupt exception",e);
			}
		}
	}
	
	private void parseTimeTable(Configuration cfg, TagNode timeFrame, CrawlerDefaultEntity station, URI timetable, CrawlerDefaultEntity busLine) throws XPatherException, RepositoryException{
		Object[] objects = timeFrame.evaluateXPath(cfg.getPathToTime());
		for(Object obj : objects){
			TagNode tg = (TagNode) obj;
			TagNode hTg = (TagNode)tg.evaluateXPath(cfg.getPathToHour())[0];
			String hour = hTg.getText().toString();
			Integer hourInt = Integer.valueOf(hour);
			Object[] object = tg.evaluateXPath(cfg.getPathToMinute());
			for(Object objs:object){
				TagNode tgn = (TagNode)objs;
				if(!tgn.getText().toString().isEmpty()){
					System.out.print(tgn.getText().toString()+"  ");
					Integer minuteInt = Integer.valueOf(tgn.getText().toString());  
					URI depart = dao.createDepart(hourInt, minuteInt, station.getName(), busLine.getName());
					dao.addDepartToTimeTable(timetable, depart);
			}	
			}
			System.out.println("");
		}
		
	}
	
	private TagNode evaluateXPath(TagNode tagNode, String xpath) throws XPatherException{
		Object[] objects = tagNode.evaluateXPath(xpath);
		TagNode tg = (TagNode)objects[0];
		return tg;
	}
	

}
